package com.elasticsearch.config;

import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONObject;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse.AnalyzeToken;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.mlt.MoreLikeThisRequestBuilder;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.highlight.HighlightField;

import de.spinscale.elasticsearch.action.suggest.suggest.SuggestAction;
import de.spinscale.elasticsearch.action.suggest.suggest.SuggestRequest;

/**
 * 
 * @ClassName: ElasticsearchUtil
 * @Description:elasticsearch数据操作工具类
 * @author kangj@doone.com.cn
 * @date 2013-12-14 下午3:19:50
 * 
 */
public class ElasticsearchUtil {

	static Log log = LogFactory.getLog(ElasticsearchUtil.class);
	/**
	 * 客户端对象
	 */
	private static TransportClient client = InitES.initESClient();
	
	static ElasticsearchUtil instance;
	
	 public static ElasticsearchUtil getInstance() {
	        synchronized (ElasticsearchUtil.class) {
	            if (instance == null) {
	                instance = new ElasticsearchUtil();
	            }
	       }
	      return instance;
	  }

	/**
	 * 
	 * @Title: createIndex
	 * @Description: 创建索引
	 * @param list
	 *            :数据对象
	 * @param indexName
	 *            ：数据库
	 * @param typeName
	 *            ：数据表
	 * @return int
	 * @author kangj@doone.com.cn
	 * @throws Exception 
	 * @date 2014-6-5 下午2:21:31
	 */
	public static int createIndex(List<?> list, String indexName,
			String typeName) throws Exception {
		int successResult = 0;

		BulkRequestBuilder bulkRequest = client.prepareBulk();

		for (Object obj : list) {
			successResult++;
			JSONObject jsonObject = JSONObject.fromObject(obj);
			bulkRequest.add(client.prepareIndex(indexName, typeName).setSource(jsonObject.toString()));
		}
		BulkResponse bulkResponse = bulkRequest.execute().actionGet();
		if (!bulkResponse.hasFailures()) {
			return successResult;
		} else {
			log.error(bulkResponse.buildFailureMessage());
		}
		return successResult;
	}
	
	
	/**
	 * 
	 * @Title: searcher
	 * @Description: 搜索方法
	 * @param indexname
	 *            :类似数据库
	 * @param type
	 *            ：类似数据表
	 * @param nowPage
	 * @param pageSize
	 * @param keyWord
	 * @return SearchResponse
	 * @author kangj@doone.com.cn
	 * @date 2013-12-21 下午5:09:05
	 */
	public static SearchResponse searcher(String indexname, String type,
			int nowPage, int pageSize, String keyWord, String[] highFields) {

		SearchResponse response = null;

		if (client != null) {
			// 创建查询索引
			SearchRequestBuilder searchRequestBuilder = client
					.prepareSearch(indexname);
			// 设置查询索引表名称
			searchRequestBuilder.setTypes(type);
			// 设置查询类型
			// 1.SearchType.DFS_QUERY_THEN_FETCH = 精确查询
			// 2.SearchType.SCAN = 扫描查询,无序
			// 3.SearchType.COUNT = 不设置的话,这个为默认值,还有的自己去试试吧
			searchRequestBuilder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);

			// fieldQuery 这个必须是你的索引字段哦,不然查不到数据,这里我只设置两个字段 id ,title
			// String title = "title+-&&||!(){}[]^\"~*?:\\";
			keyWord = QueryParser.escape(keyWord);// 主要就是这一句把特殊字符都转义,那么lucene就可以识别

			// 查询过滤器过滤价格在4000-5000内
			// 这里范围为[4000,5000]区间闭包含,搜索结果包含价格为4000和价格为5000的数据
			// searchRequestBuilder.setFilter(FilterBuilders.rangeFilter("price")
			// .from(4000).to(5000));

			/** 多条件 **/
			// BoolQueryBuilder qb = QueryBuilders.boolQuery()
			// .must(new QueryStringQueryBuilder("北京").field("body"))
			// .should(new QueryStringQueryBuilder("太多").field("body"));
			// searchRequestBuilder.setQuery(qb);

			// SearchResponse response = builder.execute().actionGet();
			// System.out.println(response.getHits().getTotalHits());

			// 设置查询数据的位置,分页用吧
			searchRequestBuilder.setFrom(nowPage);
			// 设置查询结果集的最大条数
			searchRequestBuilder.setSize(pageSize);
			// 设置是否按查询匹配度排序
			searchRequestBuilder.setExplain(true);

			// 高亮字段
			for (String field : highFields) {
				searchRequestBuilder.addHighlightedField(field);
			}

			searchRequestBuilder
					.setHighlighterPreTags("<font style='color:red'>");
			searchRequestBuilder.setHighlighterPostTags("</font>");

			// QueryStringQueryBuilder queryBuilder = new
			// QueryStringQueryBuilder(keyWord);//查询的词
			// queryBuilder.field("description").boost(0.1f);
			// searchRequestBuilder.setQuery(queryBuilder);

			// MoreLikeThisRequestBuilder mlt = new
			// MoreLikeThisRequestBuilder(client, "indexName", "indexType",
			// "id");
			// mlt.setField("title");//匹配的字段
			// SearchResponse response =
			// client.moreLikeThis(mlt.request()).actionGet();
			
			
//			MatchQueryBuilder match=new MatchQueryBuilder("content", keyWord);
//			match.analyzer("ik");
//			client.prepareSearch("test").setQuery(match).execute().actionGet();
			
			
	/*		 QueryBuilder qb2 = boolQuery()   
                     .must(termQuery("content", "test1"))   
                     .must(termQuery("content", "test4"))   
                     .mustNot(termQuery("content", "test2"))   
                     .should(termQuery("content", "test3"));   
          
 QueryBuilder qb3 = filteredQuery(   
             termQuery("name.first", "shay"),    
             rangeFilter("age")   
                 .from(23)   
                 .to(54)   
                 .includeLower(true)   
                 .includeUpper(false)   
             );*/

			// 设置查询关键词
			// fieldQuery 这个必须是你的索引字段哦,不然查不到数据,这里我只设置两个字段 id ,title
			searchRequestBuilder.setQuery(QueryBuilders.fuzzyQuery(
					"content", keyWord).boost(0.1f));
			
		
			// searchRequestBuilder.setQuery(QueryBuilders.queryString(keyWord)
			// .boost(0.1f));

			// 最后就是返回搜索响应信息
			response = searchRequestBuilder.execute().actionGet();
			// try {
			// //防止出现：远程主机强迫关闭了一个现有的连接
			// Thread.sleep(20);
			// } catch (InterruptedException e) {
			// e.printStackTrace();
			// }
		}
		return response;
	}

	/**
	 * 
	 * @Title: moreLikeThis
	 * @Description: 类似记录匹配
	 * @param indexname
	 * @param type
	 * @return SearchResponse
	 * @author kangj@doone.com.cn
	 * @date 2014-3-19 下午4:48:27
	 */
	public static SearchResponse moreLikeThis(String indexname, String type) {
		SearchResponse searchResponse = null;
		if (client != null) {
			MoreLikeThisRequestBuilder moreLikeThis = new MoreLikeThisRequestBuilder(
					client, indexname, type, "O5rg4PahSry1NSYBqLk--Q");
			searchResponse = moreLikeThis.setField("title", "content")
					.setSearchFrom(0).setSearchSize(5).execute().actionGet();

			// searchResponse = client
			// .prepareMoreLikeThis("anynote", "post", "id")
			// .setField("title", "content")
			// .setSearchFrom(0).setSearchSize(10).execute().actionGet();
			if (searchResponse != null) {
				long total = searchResponse.getHits().totalHits();
				System.out.println("命中总数：" + total);
			}

			// Float usetime = searchResponse.getTookInMillis()/1000f;
			// // 命中记录数
			// Long hits = searchResponse.getHits().totalHits();
			// for (SearchHit hit : searchResponse.getHits()) {
			//
			// // 打分
			// Float score = hit.getScore();
			// // 文章id
			// Integer id =
			// Integer.parseInt(hit.getSource().get("id").toString());
			//
			// String title = hit.getSource().get("title").toString();
			//
			// String content = hit.getSource().get("content").toString();
			// // 文章更新时间
			// Long updatetime =
			// Long.parseLong(hit.getSource().get("updatetime").toString());
			// }
		}
		return searchResponse;
	}

	/**
	 * 
	 * @Title: pinYinSearcher
	 * @Description: 拼音关键字检索
	 * @return
	 * @throws IOException
	 *             AnalyzeResponse
	 * @author kangj@doone.com.cn
	 * @date 2014-6-4 下午2:47:54
	 */
	public static AnalyzeResponse pinYinSearcher() throws IOException {
		AnalyzeResponse analyzeResponse = null;
		if (client != null) {
			// mmseg
			analyzeResponse = client.admin().indices()
					.prepareAnalyze("anynote", "中国").setAnalyzer("pinyin")
					.execute().actionGet();
			// logger.info("size:{}", analyzeResponse.getTokens().size());
			List<AnalyzeToken> list = analyzeResponse.getTokens();
			for (AnalyzeToken token : list) {
				System.out.println("拼音搜索：" + token.getTerm());
			}
		}
		return analyzeResponse;
	}

	/**
	 * 
	 * @Title: get
	 * @Description: 获取单条记录
	 * @param indexname
	 * @param type
	 * @param id
	 * @return String
	 * @author kangj@doone.com.cn
	 * @date 2013-12-29 下午2:32:33
	 */
	public static String get(String indexname, String type, String id) {
		if (client != null) {
			// 在这里创建我们要索引的对象
			GetResponse response = client.prepareGet(indexname, type, id)
					.execute().actionGet();

			System.out.println("response.getSource()：" + response.getSource());
			System.out.println("response.getId():" + response.getId());
			System.out.println("response.getSourceAsString():"
					+ response.getSourceAsString());
			return response.getSourceAsString();
		}
		return null;
	}

	/**
	 * 
	 * @Title: update
	 * @Description: 更新索引记录
	 * @param request
	 * @return String
	 * @author kangj@doone.com.cn
	 * @date 2014-3-18 上午11:15:10
	 */
	public static String update(UpdateRequest request) {
		if (client != null) {
			// 在这里创建我们要索引的对象
			client.update(request);
		}
		return null;
	}

	/**
	 * 
	 * @Title: delete
	 * @Description: 根据记录ID删除
	 * @param indexname
	 * @param type
	 * @param id
	 * @return Map<String,Object>
	 * @author kangj@doone.com.cn
	 * @date 2013-12-29 下午2:39:56
	 */
	public static Map<String, Object> delete(String indexname, String type,
			String id) {
		if (client != null) {
			// 在这里创建我们要索引的对象
			DeleteResponse response = client.prepareDelete(indexname, type, id)
					.execute().actionGet();

			boolean isNotFound = response.isFound();
			System.out.println(isNotFound); // 返回索引是否存在,存在删除

			System.out.println(response.getId());
			return response.getHeaders();
		}
		return null;
	}

	/**
	 * 
	 * @Title: deleteIndexByQuery
	 * @Description: 删除指定类型下所有索引
	 * @param indexname
	 * @param type
	 *            void
	 * @author kangj@doone.com.cn
	 * @date 2013-12-29 下午2:46:26
	 */
	public static void deleteIndexByQuery(String indexname, String type) {
		if (client != null) {
			MatchAllQueryBuilder allQueryBuilder = QueryBuilders
					.matchAllQuery();// 查询所有的documents
			// 现在把blog索引post类型的索引全部删除,由于用了QueryBuilders.matchAllQuery(),匹配所有blog
			// post下的索引
			// client.prepareDeleteByQuery(indexname).setQuery(allQueryBuilder)
			// .setTypes(type).execute().actionGet();

			client.prepareDeleteByQuery(indexname).setQuery(allQueryBuilder)
					.execute().actionGet();
		}
	}

	/**
	 * 
	 * @Title: findSuggestions
	 * @Description: 关键字搜索提示
	 * @param indexName
	 * @param field
	 * @param keyword
	 * @param size
	 * @param indices
	 * @return
	 * @throws Exception
	 *             List<String>
	 * @author kangj@doone.com.cn
	 * @date 2014-3-28 下午1:42:31
	 */
	public static List<String> findSuggestions(String indexName, String field,
			String keyword, Integer size, float indices) throws Exception {
		List<String> suggests = null;
		if (client != null) {
			// suggests = new SuggestRequestBuilder(client).setIndices(indices)
			// .field(field).term(keyword).size(size).similarity(0.5f).execute().actionGet()
			// .getSuggestions();
			SuggestRequest request = new SuggestRequest(indexName);
			request.term(keyword);
			request.field(field);
			request.size(size);
			request.similarity(indices);
			// request.analyzer("standard");
			// SuggestResponse response = client.execute(SuggestAction.INSTANCE,
			// request).actionGet();
			suggests = client.execute(SuggestAction.INSTANCE, request)
					.actionGet().getSuggestions();
			log.info("模糊匹配：" + suggests);
		}
		return suggests;
	}

	/**
	 * 
	 * @Title: getHighlightFields
	 * @Description: 获取带有关键字高亮的内容信息
	 * @param hit
	 *            :记录行
	 * @param field
	 *            :字段
	 * @return String
	 * @author kangj@doone.com.cn
	 * @date 2014-3-18 上午11:17:09
	 */
	public static String getHighlightFields(SearchHit hit, String field) {
		String content = "";
		if (hit != null) {
			Map<String, HighlightField> result = hit.highlightFields();
			HighlightField contentField = result.get(field);
			if (contentField != null) {
				Text[] contentTexts = contentField.fragments();
				for (Text text : contentTexts) {
					content = text.toString();
				}
			} else {
				content = (String) hit.getSource().get(field);
			}
		}
		return content;
	}

	
	/**
	 * 
	 * @return：创建索引
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static String createIndex() throws ElasticsearchException,
			IOException {
		IndexResponse response = client
				.prepareIndex("comment_index", "comment_ugc", "comment_123674")
				.setSource(
						XContentFactory.jsonBuilder().startObject()
								.field("author", "569874")
								.field("author_name", "riching")
								.field("mark", 232)
								.field("body", "北京不错，但是人太多了")
								.field("createDate", "20130801175520")
								.field("valid", true).endObject()).setTTL(8000)
				.execute().actionGet();
		
		//properties下面的为索引里面的字段，type为数据类型，store为是否存储，"index":"not_analyzed"为不对该字段进行分词
	     XContentBuilder mapping = XContentFactory.jsonBuilder()
         .startObject()
           .startObject("productIndex")
           .startObject("properties")       
             .startObject("title").field("type", "string").field("store", "yes").endObject()  
             .startObject("description").field("type", "string").field("index", "not_analyzed").endObject()
             .startObject("price").field("type", "double").endObject()
             .startObject("onSale").field("type", "boolean").endObject()
             .startObject("type").field("type", "integer").endObject()
             .startObject("createDate").field("type", "date").endObject()               
           .endObject()
          .endObject()
        .endObject();
	   PutMappingRequest mappingRequest = Requests.putMappingRequest("productIndex").type("productIndex").source(mapping);
	   client.admin().indices().putMapping(mappingRequest).actionGet();
		
		
		System.out.println(response.getId());
		return null;
	}
	
	

	/**
	 * 
	 * @return:索引settings
	 * @throws Exception
	 */
	public static String getAnalysisSettings() throws Exception {
		XContentBuilder mapping = XContentFactory
				.jsonBuilder()
				.startObject()
				// 主分片数量
				.field("number_of_shards", 5)
				.field("number_of_replicas", 0)
				.startObject("analysis")
				.startObject("filter")
				// 创建分词过滤器
				.startObject("pynGram")
				.field("type", "nGram")
				// 从1开始
				.field("min_gram", 1).field("max_gram", 15)
				.endObject()
				.endObject()

				.startObject("analyzer")
				// 拼音analyszer
				.startObject("pyAnalyzer").field("type", "custom")
				.field("tokenizer", "standard")
				.field("filter", new String[] { "lowercase", "pynGram" })
				.endObject().endObject().endObject().endObject();
		System.out.println(mapping.string());
		return mapping.string();
	}

	/**
	 * 定义mapping 一旦定义，之后就不能修改。
	 * 
	 * @return
	 * @throws Exception
	 */
	/*public static XContentBuilder getMapping() throws Exception {
		client.admin().indices().prepareCreate("productIndex").execute()
				.actionGet();
		XContentBuilder mapping = XContentFactory.jsonBuilder().startObject()
				.startObject("productIndex").startObject("properties")
				.startObject("title").field("type", "string")
				.field("store", "yes").endObject().startObject("description")
				.field("type", "string").field("index", "not_analyzed")
				.endObject().startObject("price").field("type", "double")
				.endObject().startObject("onSale").field("type", "boolean")
				.endObject().startObject("type").field("type", "integer")
				.endObject().startObject("createDate").field("type", "date")
				.endObject().startObject("name").field("type", "string")
				.field("analyzer", "pinyin_analyzer").endObject().endObject()
				.endObject().endObject();
		PutMappingRequest mappingRequest = Requests
				.putMappingRequest("productIndex").type("productIndex")
				.source(mapping);
		client.admin().indices().putMapping(mappingRequest).actionGet();
		return mapping;
	}*/

	// static final String INDEX_NAME="code";
	// static final String TYPE_NAME="icd";
	//
	// public static void main(String[] argv) throws Exception{
	// Client client = ESUtils.getCodeClient();
	// Builder settings = ImmutableSettings.settingsBuilder()
	// .loadFromSource(getAnalysisSettings());
	// //首先创建索引库
	// CreateIndexResponse indexresponse = client.admin().indices()
	// //这个索引库的名称还必须不包含大写字母
	// .prepareCreate(INDEX_NAME).setSettings(settings)
	// //这里直接添加type的mapping
	// .addMapping(TYPE_NAME, getMapping())
	// .execute().actionGet();
	//
	// System.out.println("success:"+indexresponse.isAcknowledged());
	// }

	public static void main(String[] args) throws Exception {
		//get("jdbc", "jdbc", "R_yxw19eQeC040b74eCExA");

		// 关键词搜索
		String[] highFields = new String[] { "content" };
		// SearchResponse response= searcher("medcl", "folks", 0, 1, "中俄",
		// highFields);
		SearchResponse response = searcher("anynote", "post", 0, 10, "中国",
				highFields);
		long total = response.getHits().totalHits();
		System.out.println(total);

		// if (client != null) {
		// // 在这里创建我们要索引的对象
		// GetResponse response = client
		// .prepareGet("anynote", "post", "2Wa0VBIHT5ek-O0ri2MbEg")
		// .execute().actionGet();
		//
		// System.out.println("response.getSource()：" + response.getSource());
		//
		// UpdateRequest update = new UpdateRequest();
		// update.upsert(response.getSource());
		// }
		// float indices = (float) 0.9;
		// System.out.println(findSuggestions("anynote","title", "中", 10,
		// (float) 0.1));
		// System.out.println(findSuggestions("anynote","content", "zhong", 5,
		// 0.1f));
		// pinYinSearcher();

		// moreLikeThis("anynote", "post");
		// deleteIndexByQuery("medcl","news");
	}
}
